import 'dart:convert';

import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
import 'package:shimo_app/pages/components/confirmdDialog.dart';
import 'package:shimo_app/services/device_service.dart';

import '../../../services/db_service.dart';
import '../../components/hint.dart';
import 'function_state.dart';
import 'dart:io';

class FunctionController extends GetxController {
  final FunctionState state = FunctionState();
  String taskName = "null";
  String newTaskName = "";
  int selectedFunction = 0;
  List<ParamStruct> displayParams = [];
  List<int> paramValues = [];
  List<Map<int, List<int>>> functionList = [];
  List<Map<String, List<Map<int, List<int>>>>> taskList = [];
  List<List<String>> displayFunctionList = [];
  int selectedItemIndex = -1;
  List<List<Map<int, List<int>>>> useFunctionList = [[], []];
  List<List<List<String>>> useFunctionLabelList = [[], []];
  final List<TextEditingController> inputControllers = [];
  final List<String> channelAlias = List.generate(10, (index) => "");
  final List<String> inputChannelAlias = List.generate(10, (index) => "");
  DbService dbService = Get.find<DbService>();
  final deviceService = Get.find<DeviceService>();
  bool isEditingChannelAlias = false;
  bool showTaskSelection = true;
  int selectedTaskIndex = 0;
  bool addMode = false;
  bool hasEditTaskFunction = false;
  File? funcFile;

  List<FunctionItem> allFunctions = [];

  @override
  void onInit() async {
    // List<String> keys = dbService.getKeysByHeader("func_");
    // for (var i in keys) {
    //   final raw = dbService.getValue<String>(i);
    //   print("func data:$raw");
    //   final name = i.split("func_")[1];
    //   if (raw == null) {
    //     taskList.add({name: []});
    //   } else {
    //     try {
    //       final al = jsonDecode(raw);
    //
    //       for (var ii in al) {
    //         List<Map<int, List<int>>> l1 = [];
    //         for (var j in ii["funcs"]) {
    //           Map<int, List<int>> m2 = {};
    //           m2[j["funcId"]] = j["params"].cast<int>();
    //           l1.add(m2);
    //         }
    //         Map<String, List<Map<int, List<int>>>> m1 = {ii["name"]: l1};
    //         taskList.add(m1);
    //       }
    //     } catch (e) {
    //       print("err:$e");
    //     }
    //   }
    // }

    // final raw = dbService.getValue<String>("funcList");
    final raw = await getLocalFuncList();
    print("raw:${raw}");
    if (raw != null) {
      try {
        final al = jsonDecode(raw);

        for (var ii in al) {
          List<Map<int, List<int>>> l1 = [];
          for (var j in ii["funcs"]) {
            Map<int, List<int>> m2 = {};
            m2[j["funcId"]] = j["params"].cast<int>();
            l1.add(m2);
          }
          Map<String, List<Map<int, List<int>>>> m1 = {ii["name"]: l1};
          taskList.add(m1);
        }
      } catch (e) {
        print("err:$e");
      }
    }
    selectedFunction = 0;
    for (var i = 0; i < 5; i++) {
      inputControllers.add(TextEditingController());
    }
    for (var i = 0; i < channelAlias.length; i++) {
      final v = dbService.getValue<String>("channel alias:$i");
      if (v == null) {
        continue;
      }
      channelAlias[i] = v;
    }
    print("===$channelAlias");
    allFunctions = [
      FunctionItem("加液", [
        ParamStruct(
          "试剂",
          ParamType.select,
          "N/A",
          "channel",
          options: List.generate(
              10,
              (index) => channelAlias[index].isEmpty
                  ? "试剂${index + 1}"
                  : channelAlias[index]),
        ),
        ParamStruct("用量", ParamType.floatInput, "ml", "dosage"),
      ]),
      FunctionItem("加热", [
        ParamStruct("目标温度", ParamType.integerInput, "℃", "tempr"),
        ParamStruct("升温时间", ParamType.integerInput, "min", "w dur"),
        ParamStruct("平衡时间", ParamType.integerInput, "min", "d dur"),
      ]),
      // FunctionItem("摇匀", [
      //   ParamStruct("速度", ParamType.select, "N/A", "m dur",
      //       options: ["低速", "中速", "高速"]),
      //   ParamStruct("时间", ParamType.numberInput, "min", "mix speed"),
      // ]),
      FunctionItem("冷却", [
        ParamStruct("时间", ParamType.integerInput, "min", "cold t"),
      ]),
      FunctionItem("清洗", [
        ParamStruct("试剂", ParamType.select, "N/A", "clean c",
            options: List.generate(
                10,
                (index) => channelAlias[index].isEmpty
                    ? "试剂${index + 1}"
                    : channelAlias[index])),
        ParamStruct("用量", ParamType.integerInput, "ml", "clean d"),
      ]),
      FunctionItem("定容", [
        ParamStruct("试剂", ParamType.select, "N/A", "det ch",
            options: List.generate(
                10,
                (index) => channelAlias[index].isEmpty
                    ? "试剂${index + 1}"
                    : channelAlias[index])),
        ParamStruct("定容量", ParamType.integerInput, "ml", "det do"),
      ]),
      FunctionItem("静置", [
        ParamStruct("时间", ParamType.integerInput, "min", "det do"),
      ]),
      // FunctionItem("洗罐", [
      //   ParamStruct("试剂", ParamType.select, "N/A", 'shiji',
      //       options: List.generate(
      //           10,
      //           (index) => channelAlias[index].isEmpty
      //               ? "试剂${index + 1}"
      //               : channelAlias[index])),
      //   ParamStruct("计量", ParamType.numberInput, "ml", "jiliang"),
      //   ParamStruct("循环次数", ParamType.numberInput, "次", "cishu"),
      // ])
      FunctionItem("摇匀", [
        ParamStruct("速度", ParamType.select, "N/A", "m dur",
            options: ["低速", "中速", "高速"]),
        ParamStruct("时间", ParamType.integerInput, "min", "mix speed"),
      ]),
    ];
    showParams();
    super.onInit();
  }

  @override
  void onClose() {
    for (var i in inputControllers) {
      i.dispose();
    }
    super.onClose();
  }

  Future<String?> getLocalFuncList() async {
    final path = deviceService.funcPath;
    if (path != null) {
      final funcDir = Directory(path);
      if (funcDir.existsSync()) {
        final f = File("$path\\functions");
        if (!f.existsSync()) {
          print("创建文件");
          await f.create();
        }
        funcFile = f;
      }
    }
    if (funcFile == null) {
      return dbService.getValue<String>("funcList");
    }
    return funcFile?.readAsStringSync();
  }

  void setLocalFuncList(String str) {
    if (funcFile == null) {
      dbService.setValue("funcList", str);
      return;
    }
    funcFile?.writeAsStringSync(str);
  }

  void addTask(String name) {
    if (functionList.isEmpty) {
      showHint("没有添加任务，无法保存", HintType.DANGER);
      return;
    }
    final existedTaskIndex =
        taskList.indexWhere((element) => element.keys.first == name);
    if (existedTaskIndex != -1) {
      showHint("方法名称重复", HintType.DANGER);
      return;
    }
    final newFuncs = [...functionList];
    taskList.add({name: newFuncs});
    List<Map> al = [];
    for (var i in taskList) {
      for (var j in i.keys) {
        Map<String, dynamic> m = {};
        m["name"] = j;
        List<Map> funcList = [];
        for (var k in i[j]!) {
          Map<String, dynamic> funcMap = {};
          for (var l in k.keys) {
            funcMap['funcId'] = l;
            funcMap['params'] = k[l];
          }
          funcList.add(funcMap);
        }
        m["funcs"] = funcList;
        al.add(m);
      }
    }
    final str = json.encode(al);
    print("task str:$str");
    taskName = taskList.first.keys.first;
    // dbService.setValue("funcList", str);
    setLocalFuncList(str);
    showHint("保存成功", HintType.SUCCESS);
  }

  void saveTask(String oldName, String newName) {
    if (functionList.isEmpty) {
      showHint("没有添加任务，无法保存", HintType.DANGER);
      return;
    }
    final existedTaskIndex =
        taskList.indexWhere((element) => element.keys.first == oldName);
    print(existedTaskIndex);
    if (existedTaskIndex == -1) {
      showHint("方法不存在，无法修改", HintType.DANGER);
      return;
    }
    final conflictIndex =
        taskList.indexWhere((element) => element.keys.first == newName);
    if (conflictIndex != -1 && existedTaskIndex != conflictIndex) {
      showHint("方法名称重复，无法修改", HintType.DANGER);
      return;
    }
    final newFuncs = [...functionList];
    // if (existedTaskIndex != -1) {
    taskList[existedTaskIndex] = {newName: newFuncs};
    // } else {
    //   taskList.add({newName: newFuncs});
    // }
    print("tasks:${taskList.toString()}");
    List<Map> al = [];
    for (var i in taskList) {
      for (var j in i.keys) {
        Map<String, dynamic> m = {};
        m["name"] = j;
        List<Map> funcList = [];
        for (var k in i[j]!) {
          Map<String, dynamic> funcMap = {};
          for (var l in k.keys) {
            funcMap['funcId'] = l;
            funcMap['params'] = k[l];
          }
          funcList.add(funcMap);
        }
        m["funcs"] = funcList;
        al.add(m);
      }
    }
    print("${newName} task str:$al");
    // dbService.setValue("funcList", json.encode(al));
    // dbService.removeKey("func_${oldName}");
    setLocalFuncList(json.encode(al));
    taskName = newName;
    showHint("保存成功", HintType.SUCCESS);
  }

  Future saveTaskFunctions(String taskName) async {
    final existedTaskIndex =
        taskList.indexWhere((element) => element.keys.first == taskName);
    print("--${taskName}==${taskList}");
    print(existedTaskIndex);
    if (existedTaskIndex == -1) {
      showHint("方法不存在，无法修改", HintType.DANGER);
      return;
    }
    taskList[existedTaskIndex] = {
      taskName: [...functionList]
    };
    List<Map> al = [];
    for (var i in taskList) {
      for (var j in i.keys) {
        Map<String, dynamic> m = {};
        m["name"] = j;
        List<Map> funcList = [];
        for (var k in i[j]!) {
          Map<String, dynamic> funcMap = {};
          for (var l in k.keys) {
            funcMap['funcId'] = l;
            funcMap['params'] = k[l];
          }
          funcList.add(funcMap);
        }
        m["funcs"] = funcList;
        al.add(m);
      }
    }
    print("task str:$al");
    // dbService.removeKey("func_${taskName}");
    // await 10.milliseconds.delay();
    // dbService.setValue("funcList", json.encode(al));
    setLocalFuncList(json.encode(al));
    showHint("保存成功", HintType.SUCCESS);
    hasEditTaskFunction = false;
    update();
  }

  void removeTask(int index) async {
    if (taskList.isEmpty) {
      showHint("不存在无法删除", HintType.DANGER);
      return;
    }
    if (!await showConfirmDialog("确定删除?")) return;
    print("delete ${taskList[index].keys.first}");
    selectedTaskIndex = 0;
    dbService.removeKey(taskList[index].keys.first);

    taskList.removeAt(index);
    // dbService.setValue("funcList", jsonEncode(taskList));
    // setLocalFuncList(jsonEncode(taskList));
    functionList.clear();
    displayFunctionList = generateFunctionItem();
    taskName = "null";
    selectedItemIndex = -1;
    update();
    showHint("删除成功", HintType.SUCCESS);
  }

  void selectTask(int index) {
    if (index + 1 > taskList.length) {
      return;
    }
    print("tasks:$taskList");
    functionList = [...taskList[index].values.first];
    displayFunctionList = generateFunctionItem();
    selectedItemIndex = -1;
    update();
    showHint("选择成功", HintType.SUCCESS);
  }

  void refreshData() {
    functionList.clear();
    displayFunctionList.clear();
    taskName = "null";
    showTaskSelection = true;
    selectedTaskIndex = 0;
    hasEditTaskFunction = false;
    selectedItemIndex = -1;
    update();

    super.refresh();
  }

  void setChannelAlias() {
    for (var i = 0; i < inputChannelAlias.length; i++) {
      if (inputChannelAlias[i].isEmpty) {
        continue;
      }
      channelAlias[i] = inputChannelAlias[i];
      dbService.setValue("channel alias:$i", inputChannelAlias[i]);
      inputChannelAlias[i] = "";
    }
    for (var i in allFunctions) {
      for (var j in i.params) {
        if (j.label != "试剂") continue;
        j.options = List.generate(
            10,
            (index) => channelAlias[index].isEmpty
                ? "试剂${index + 1}"
                : channelAlias[index]);
        print("optins:${j.options}");
      }
    }
    isEditingChannelAlias = false;
    update();
  }

  void showParams() {
    displayParams =
        List<ParamStruct>.from(allFunctions[selectedFunction].params);
    paramValues = List.generate(displayParams.length, (index) => 0);
    update();
  }

  void addFunction() {
    int index = -1;
    for (var i in displayParams) {
      index++;
      if (i.type == ParamType.integerInput && paramValues[index] <= 0) {
        showHint("参数<${i.label}>未配置", HintType.DANGER);
        return;
      }
    }
    /******************************************************************
     * 以定容为例，添加定容任务后的functionList
     * 如6是"定容"在allFunctions中的索引，[0,100]对应[试剂索引, 定容量]
     * functionList = [{6: [0, 100]} ] 
     * displayFunctionList = [
          ["定容", "试剂", "试剂1", "N/A", "定容量", "100", "ml"]
        ]
     ******************************************************************/
    functionList.add({selectedFunction: List.from(paramValues)});
    displayFunctionList = generateFunctionItem();
    hasEditTaskFunction = true;
    selectedItemIndex = -1;
    update();
  }

  void insertFunction(bool front) {
    if (selectedItemIndex > functionList.length - 1) {
      selectedItemIndex = -1;
      update();
      return;
    }
    int index = -1;
    for (var i in displayParams) {
      index++;
      if (i.type == ParamType.integerInput && paramValues[index] <= 0) {
        showHint("参数<${i.label}>未配置", HintType.DANGER);
        return;
      }
    }
    int insertIndex = front ? selectedItemIndex : selectedItemIndex + 1;
    if (insertIndex > functionList.length - 1) {
      insertIndex = functionList.length - 1;
    }
    if (front) {
      selectedItemIndex++;
    }
    functionList
        .insert(insertIndex, {selectedFunction: List.from(paramValues)});
    displayFunctionList = generateFunctionItem();
    hasEditTaskFunction = true;
    selectedItemIndex = -1;
    update();
  }

  void deleteFunction(int index) {
    if (index > functionList.length - 1) {
      return;
    }
    if (selectedItemIndex > index) {
      selectedItemIndex--;
    } else if (selectedItemIndex == index) {
      selectedItemIndex = -1;
    }
    functionList.removeAt(index);
    displayFunctionList = generateFunctionItem();
    hasEditTaskFunction = true;
    selectedItemIndex = -1;
    update();
  }

  List<List<String>> generateFunctionItem() {
    List<List<String>> items = [];
    print(functionList);
    for (var i in functionList) {
      List<String> item = [];
      final functionIndex = i.keys.toList()[0]; // 获取功能索引
      item.add(allFunctions[functionIndex].name); //获取功能名称
      int ii = -1;
      for (ParamStruct p in allFunctions[functionIndex].params) {
        ii++;
        item.addAll([
          p.label,
          p.type == ParamType.select
              ? (p.options![i[functionIndex]![ii]])
              : (p.type == ParamType.floatInput
                  ? (i[functionIndex]![ii] / 10).toStringAsFixed(1)
                  : i[functionIndex]![ii].toString()),
          p.unit
        ]);
      }
      items.add(item);
    }
    print(items);
    return items;
  }

  String getParamTag(int funcIndex, int paramIndex) {
    if (funcIndex >= allFunctions.length) {
      return "";
    }
    if (paramIndex >= allFunctions[funcIndex].params.length) {
      return "";
    }
    return allFunctions[funcIndex].params[paramIndex].tag;
  }

// Future<bool> saveFunction(String name, List<String> items) async {
//
// }
}

enum ParamType { integerInput, floatInput, select }

class ParamStruct {
  final String label;
  final ParamType type;
  final String unit;
  final String tag;
  List<String>? options;

  ParamStruct(this.label, this.type, this.unit, this.tag, {this.options});
}

class FunctionItem {
  final String name;
  final List<ParamStruct> params;

  FunctionItem(this.name, this.params);
}
